package com.augurit.common.dao;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Repository;

import com.augurit.common.base.dao.BaseDao;
import com.augurit.common.constant.OrgConstant;
import com.augurit.common.entity.AcModule;
import com.augurit.common.system.convert.AcModuleConverter;
import com.augurit.common.system.web.org.form.AcModuleForm;
import com.augurit.common.util.lang.CollectionUtils;
import com.augurit.common.util.lang.StringUtils;

/**
 * 模块DAO类
 */
@Repository
public class AcModuleDao extends BaseDao<AcModule, Long> {

	/**
	 * 根据主键ID获取模块Form对象
	 * @param id
	 * @return
	 */
	public AcModuleForm getForm(Long id){
		AcModuleForm form = null;
		if(id != null){
			AcModule entity = this.get(id);
			if(entity != null)
				form = AcModuleConverter.convertToForm(entity);
			
			if(entity.getParentModuleId() != null){
				form.setParentModuleName(this.get(entity.getParentModuleId()).getModuleName());
			}
		}

		return form;
	}
	
	/**
	 * 级联添加模块
	 * @param form 模块form对象
	 */
	public void addModuleCascade(AcModuleForm form){
		if(form != null){
			
			//更新父模块
			AcModule parentModule = null;
			if(form.getParentModuleId() != null){
				//获取父模块对象
				parentModule = this.get(form.getParentModuleId());
				//更新其父模块IS_LEAF和SUB_COUNT上的值
				updateModuleAfterAddChildren(parentModule);
			}
			
			//保存模块并获取主键ID
			form.setModuleLevel(parentModule != null ? parentModule.getModuleLevel() + 1 : 1);
			form.setAppId(parentModule != null ? parentModule.getAppId() : form.getAppId());
			save(form);
			
			//更新模块序列
			form.setModuleSeq(calcModuleSeq(parentModule, form.getModuleId()));
			save(form);
		}
	}

	
	/**
	 * 计算模块序列，计算方法为moduleSeq = 其父模块seq + 模块主键id
	 * @param parentModuleId
	 * @param moduleId
	 * @return
	 */
	public String calcModuleSeq(AcModule parentModule, Long moduleId){
		String result = "";
		
		if(moduleId != null){
			if(parentModule != null){
				if(StringUtils.isNotBlank(parentModule.getModuleSeq())){
					result += parentModule.getModuleSeq() + moduleId + ".";
				}
			}else{
				result += "." + moduleId + ".";
			}
		}
		
		return result;
	}
	
	/**
	 * 计算模块序列
	 * @param parentModuleId
	 * @param moduleId
	 * @return
	 */
	public String calcModuleSeq(Long parentModuleId, Long moduleId){
		if(parentModuleId != null)
			return calcModuleSeq(this.get(parentModuleId), moduleId);
		else
			return "";
	}
	
	/**
	 * 保存模块Form对象
	 * @param form 模块Form对象
	 */
	public void save(AcModuleForm form){
		
		if(form != null){
			AcModule entity = null;
			
			//准备VO对象
			if(form != null && form.getModuleId() != null){
				entity = this.get(form.getModuleId());
			}else{
				entity = new AcModule();
			}
			
			//属性值转换
			AcModuleConverter.convertToEntity(form, entity);
			
			//保存
			super.save(entity);
			
			//回填ID属性值
			form.setModuleId(entity.getModuleId());
		}
	}
	
	/**
	 * 获取指定应用的模块及子模块ID集合
	 * @param appId 应用的主键id
	 * @param direct 设为true则获取应用的直属模块列表，设为false则获取应用的所有模块及子模块列表
	 * @return 返回结果值
	 */
	public Long[] getModuleIds(Long appId, boolean direct){
		if(appId != null){
			List<Long> ids = partSelectModules(appId, direct, "moduleId");
			return CollectionUtils.toLongArray(ids);
		}else
			return null;
	}	
	
	/**
	 * 获取指定应用的模块及子模块Entity对象列表
	 * @param appId 应用的主键id
	 * @param direct 设为true则获取应用的直属模块列表，设为false则获取应用的所有模块及子模块列表
	 * @return 返回结果值
	 */
	public List<AcModule> getModules(Long appId, boolean direct){
		if(appId != null)	
			return partSelectModules(appId, direct, null);
		else
			return null;
	}
	
	/**
	 * 获取指定应用的模块并控制返回要查询的结果
	 * @param appId 应用ID
	 * @param direct 设为true则获取应用的直属模块列表，设为false则获取应用的所有模块及子模块列表
	 * @param entityProperty 返回要查询的结果。例如：要返回Entity对象的moduleId属性，则设为“moduleId”。
	 * @return
	 */
	private List partSelectModules(Long appId, boolean direct, String entityProperty){
		String hql = "select " 
						+ (entityProperty != null && entityProperty.trim().length() > 0 ? "ps." + entityProperty : "ps") 
						+ " from AcModule ps where ps.appId=? " 
						+ (direct ? "and ps.moduleLevel=1" : "")
						+ " order by ps.moduleLevel";
		List values = new ArrayList();
		values.add(appId);
		
		return this.find(hql,values);
	}
	
	/**
	 * 根据moduleId查找它的所有的子模块，（相当与找出以该结点为树根的整棵树,注意要排除树根）
	 * 注意这个是根据MODULE_SEQ来做的，是用非递归的方法
	 * @param moduleId,本模块的id
	 * @return 返回值为null表示没有找到
	 */
	public List<AcModule> getAllChildModules(Long moduleId){
		if(moduleId != null)
			return partSelectAllChildModules(moduleId, null);
		else
			return null;
	}
	
	/**
	 * 根据moduleId查找它的所有的子模块，（相当与找出以该结点为树根的整棵树,注意要排除树根）
	 * 注意这个是根据MODULE_SEQ来做的，是用非递归的方法
	 * @param moduleId,本模块的id
	 * @return 返回值为null表示没有找到
	 */
	public Long[] getAllChildModuleIds(Long moduleId){
		if(moduleId != null){
		    List<Long> ids = partSelectAllChildModules(moduleId, "moduleId");
			return CollectionUtils.toLongArray(ids);
		}else
			return null;
	}
	
	/**
	 * 获取所有子模块并控制返回要查询的结果
	 * @param moduleId
	 * @param entityProperty 返回要查询的结果。例如：要返回Entity对象的moduleId属性，则设为“moduleId”。
	 * @return
	 */
	private List partSelectAllChildModules(Long moduleId, String entityProperty){
		String hql = "select " 
						+ (entityProperty != null && entityProperty.trim().length() > 0 ? "ps." + entityProperty : "ps") 
						+ " from AcModule ps where ps.moduleSeq like ? and ps.moduleId != ?";
		List values = new ArrayList();
		values.add("%." + moduleId + ".%");
		values.add(moduleId);
		
		return this.find(hql,values);
	}
	
	/**
	 * 根据parentModuleId查找子模块
	 * @param parentModuleId 父模块的id
	 * @return 返回值为null表示没有找到
	 */
	public List<AcModule> getChildModules(Long parentModuleId){
		if(parentModuleId != null)
			return partSelectChildModules(parentModuleId, null);
		else
			return null;
	}
	
	/**
	 * 根据parentModuleId查找子模块
	 * @param parentModuleId 父模块的id
	 * @return 返回值为null表示没有找到
	 */
	public Long[] getChildModuleIds(Long parentModuleId){
		if(parentModuleId != null){
		    List<Long> ids = partSelectChildModules(parentModuleId, "moduleId");
			return CollectionUtils.toLongArray(ids);
		}else
			return null;
	}
	
	/**
	 * 获取子模块并控制返回要查询的结果
	 * @param parentModuleId
	 * @param entityProperty 返回要查询的结果。例如：要返回Entity对象的moduleId属性，则设为“moduleId”。
	 * @return
	 */
	private List partSelectChildModules(Long parentModuleId, String entityProperty){
		String hql = "select " 
						+ (entityProperty != null && entityProperty.trim().length() > 0 ? "ps." + entityProperty : "ps") 
						+ " from AcModule ps where ps.parentModuleId = ?";
		List values = new ArrayList();
		values.add(parentModuleId);
		
		return this.find(hql,values);
	}

	/**
	 * 当指定模块删除了子模块或功能后要对模块的相关计算字段进行更新
	 * @param moduleId 模块主键ID
	 */
	public void updateModuleAfterRemoveChildren(Long moduleId){
		if(moduleId != null){
			
			AcModule module = this.get(moduleId);
			
			updateModuleAfterRemoveChildren(module);
		}
	}
	
	/**
	 * 当指定模块删除了子模块或功能后要对模块的相关计算字段进行更新
	 * @param module 模块
	 */
	public void updateModuleAfterRemoveChildren(AcModule module){
		if(module != null){
			int subCount = module.getSubCount() - 1;	//子节点数减1
			
			module.setSubCount(subCount);
			if(subCount == 0)
				module.setIsLeaf(OrgConstant.ONE);		//设置为叶子节点
			else
				module.setIsLeaf(OrgConstant.ZERO);		//设置为非叶子节点
				
			this.save(module);
		}
	}
	
	/**
	 * 当指定模块添加了子模块或功能后要对模块的相关计算字段进行更新
	 * @param moduleId 模块主键ID
	 */
	public void updateModuleAfterAddChildren(Long moduleId){
		if(moduleId != null){
			AcModule module = this.get(moduleId);
			updateModuleAfterAddChildren(module);
		}
	}
	
	/**
	 * 当指定模块添加了子模块或功能后要对模块的相关计算字段进行更新
	 * @param module 模块
	 */
	public void updateModuleAfterAddChildren(AcModule module){
		if(module != null){
			int subCount = module.getSubCount() == null ? 1 : module.getSubCount() + 1;	//子节点数加1
			module.setSubCount(subCount);
			module.setIsLeaf(OrgConstant.NOT_LEAF_NODE);	//设置为非叶子节点
			this.save(module);
		}
	}
	
	/**
	 * 获取父模块id
	 * @param moduleId 模块id
	 * @return 父模块id
	 */
	public Long getParentModuleId(Long moduleId){
		if( moduleId != null){
			AcModule entity = this.get(moduleId);
			if(entity != null)
				return entity.getParentModuleId();
		}
		return null;
	}
	
	/**
	 * 获取父模块form对象
	 * @param moduleId 模块id
	 * @return 模块form对象
	 */
	public AcModuleForm getParentModule(Long moduleId){
		if(moduleId != null){
			Long parentModuleId = this.getParentModuleId(moduleId);
			return this.getForm(parentModuleId);
		}
		return null;
	}

}
